<template>
  <div>
    <h1>三级分类页面</h1>
    <p>电商分类只能为二级,拖拽之后总层数不能超过三</p>
    <p>拖拽分为两种类型: 前后,内部</p>
    <p>
      思路: 拖拽是两个节点(被拖拽的节点,目标对象)的交互<br />
      1.需要判断被拖拽的节点的层数(计算拖拽的层数) <br />
      2.需要判断拖拽类型和目标对象的层数判断(判断是否能被拖拽) <br />
      3.把拖拽之后的结果同步数据库
    </p>
    <el-switch v-model="draggable" active-text="开启拖拽" inactive-text="关闭拖拽">
    </el-switch>
    <el-tree
      :default-expanded-keys="defaultExpandedKeys"
      node-key="catId"
      @node-drop="nodeDrop"
      :allow-drop="allowDrop"
      :draggable="draggable"
      :data="data"
      :props="defaultProps"
      :expand-on-click-node="false"
      ><span class="custom-tree-node" slot-scope="{ node, data }">
        <span>{{ node.label }}</span>
        <span>
          <el-button type="text" size="mini" @click="() => append(data)">
            Append
          </el-button>
          <el-button type="text" size="mini" @click="() => update(data)">
            Update
          </el-button>
          <el-button
            type="text"
            v-if="node.childNodes.length == 0"
            size="mini"
            @click="() => remove(node, data)"
          >
            Delete
          </el-button>
        </span>
      </span>
    </el-tree>
    <!-- 添加修改弹窗 -->
    <el-dialog title="添加种类" :visible.sync="dialogFormVisible">
      <el-form :model="category">
        <el-form-item label="活动名称" label-width="120px">
          <el-input v-model="category.name" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogFormVisible = false">取 消</el-button>
        <el-button
          type="primary"
          @click="
            dialogFormVisible = false;
            save();
          "
          >确 定</el-button
        >
      </div>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data() {
    return {
      defaultExpandedKeys: [],
      draggable: false,
      updateNodes: [],
      pid: 0,
      catLevel: 1,
      level: 1,
      category: {},
      dialogFormVisible: false,
      data: [],
      defaultProps: {
        children: "children",
        label: "name"
      }
    };
  },
  created() {
    this.getDataList();
  },
  methods: {
    /**
     * draggingNode: 被拖动的节点
     * dropNode: 目标节点
     * type: before after inner
     * 因为拖拽类型不同可能会改变pid的值
     * before 或 after 那么pid为目标对象的pid
     * inner 那么pid就是目标对象的cid
     * 数据库需要修改的字段 parentCid catLevel sort
     * 前台给后台传递参数
     * 已知条件 子元素（数组）
     * 如果传递成功 dropNode 有最新的数据
     * 需要给后台传递的参数中又要根据类型判断
     * 如果拖拽类型为before after, 需要获取的对象是目标对象的父元素的子集
     * 如果是inner 需要获取目标对象的子元素
     * 获取的数据是数组 后台批量修改
     *
     * 1.第一个未知条件
     * parent_cid
     * 2.第二个未知条件
     * cat_level
     * 3.第三个未知条件
     * sort
     *
     */
    // 和数据库交互 数据同步
    nodeDrop(draggingNode, dropNode, type) {
      console.log("拖拽成功:", draggingNode, dropNode, type);

      let flag = false;
      let updateChildNode = null;
      if (type == "before" || type == "after") {
        this.pid = dropNode.data.parentCid;
        //计算层级
        if (draggingNode.data.catLevel != dropNode.data.catLevel) {
          this.level = dropNode.data.catLevel;
          flag = true;
          updateChildNode = draggingNode;
        }
        //收集元素
        if (this.pid == 0) {
          this.getUpdateNodes(dropNode.parent.data, flag, updateChildNode);
        } else {
          this.getUpdateNodes(
            dropNode.parent.data.children,
            flag,
            updateChildNode
          );
        }
      } else if (type == "inner") {
        this.pid = dropNode.data.catId;
        //计算层级
        this.level = dropNode.data.catLevel + 1;
        // 收集元素
        this.getUpdateNodes(dropNode.data.children, flag, updateChildNode);
      }
      // 查看收集之后的结果
      console.log("收集的数据为:", this.updateNodes);
      // 修改
      this.$http({
        url: this.$http.adornUrl(`/product/category/updateNodes`),
        method: "post",
        data: this.$http.adornData(this.updateNodes, false)
      }).then(({ data }) => {
        if (data.code == 0) {
          this.$message({
            message: "拖拽成功",
            type: "success"
          });
          (this.updateNodes = []), this.getDataList();
        }
      });
    },
    //收集后台需要的数据
    getUpdateNodes(nodes, flag, node, level = this.level, pid = this.pid) {
      console.log("需要被收集的元素:", nodes);
      console.log("被拖拽的对象:", node);
      for (let i = 0; i < nodes.length; i++) {
        this.updateNodes.push({
          catId: nodes[i].catId,
          name: nodes[i].name,
          parentCid: pid,
          catLevel: level,
          sort: i
        });
      }
      if (flag && node != null) {
        this.getUpdateNodes(
          node.data.children,
          false,
          null,
          this.level + 1,
          node.data.catId
        );
      }
    },
    //拖拽时判定目标节点能否被放置(next,prev inner)
    allowDrop(draggingNode, dropNode, type) {
      // 1.计算被拖拽对象的层数
      this.getCountLevel(draggingNode);
      if (type == "next" || type == "prev") {
        //拖拽判断
        if (this.catLevel == 1) return true;
        if (this.catLevel == 2 && dropNode.data.catLevel != 3) return true;
        if (this.catLevel == 3 && dropNode.data.catLevel == 1) return true;
      } else if (type == "inner") {
        if (this.catLevel == 1 && dropNode.data.catLevel != 3) return true;
        if (this.catLevel == 2 && dropNode.data.catLevel == 1) return true;
      }
      return false;
    },
    //计算当前被拖拽层级
    getCountLevel(node) {
      //被拖拽对象
      this.catLevel = 1; //初始化一级
      if (node.childNodes.length > 0) {
        this.catLevel = 2;
        for (const i in node.childNodes) {
          if (node.childNodes[i].childNodes.length > 0) {
            this.catLevel = 3;
            return;
          }
        }
      }
    },
    // 删除
    remove(node, data) {
      var ids = node.data.catId
        ? [node.data.catId]
        : this.node.data.map(item => {
            return item.catId;
          });
      this.$http({
        url: this.$http.adornUrl(`/product/category/delete`),
        method: "post",
        data: this.$http.adornData(ids, false)
      }).then(({ data }) => {
        if (data.code == 0) {
          this.$message({
            message: "保存成功",
            type: "success"
          });
          this.getDataList();
        }
      });
    },
    // 修改前的回显
    update(node) {
      this.dialogFormVisible = true;
      // 后台查询(回显)
      this.$http({
        url: this.$http.adornUrl(`/product/category/info/${node.catId}`),
        method: "get",
        params: this.$http.adornParams()
      }).then(({ data }) => {
        this.category = data.category;
      });
    },
    // 表单提交
    save() {
      let methodName = "save";
      if (this.category.catId) methodName = "update";
      this.$http({
        url: this.$http.adornUrl(`/product/category/${methodName}`),
        method: "post",
        data: this.$http.adornData(this.category, false)
      }).then(({ data }) => {
        if (data.code == 0) {
          this.$message({
            message: "保存成功",
            type: "success"
          });
          close(this.category.parentCid);
          this.defaultExpandedKeys = [this.category.parentCid]
          this.getDataList();
        }
      });
    },
    // 添加种类
    append(data) {
      this.category = {};
      this.category.parentCid = data.catId;
      this.category.catLevel = data.catLevel + 1;
      this.category.showStatus = 1;
      this.category.sort = 0;
      this.dialogFormVisible = true;
    },
    // 获取数据列表
    getDataList() {
      this.$http({
        url: this.$http.adornUrl("/product/category/tree/list"),
        method: "get",
        params: this.$http.adornParams()
      }).then(({ data }) => {
        this.data = data.page;
      });
    }
  }
};
</script>
